import URLHelper from "../URLHelper";
import otherHelpers from "../others";
import dynamicLoadScript from "../dynamicLoadScript";

const nativeWin = otherHelpers.globalWin;

let user = null;
let sdk = null;
let sdkLoadingPromise = null;
const userCacheKey = 'wx-user-info-cache-O@#90hfej2lhhfsd';

let UsedWxCustomElement = [];

export default class WechatHelper {
    static appId = '';
    static scope = '';
    static debug = false;
    static getConfig = () => null;

    static get customElement() {
        return UsedWxCustomElement.slice();
    }

    static set customElement(elements) {
        UsedWxCustomElement = elements.slice();
    }

    static get JsSDKList() {
        return Object.getOwnPropertyNames(WechatHelper).filter(k => k.endsWith('_JsSDK')).map(k => k.replace('_JsSDK', ''));
    }

    static goAuth() {
        nativeWin?.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this.appId}&redirect_uri=${
            encodeURIComponent(URLHelper.current.toString())
        }&response_type=code&scope=${this.scope}&state=STATE#wechat_redirect`;
    }

    static getCode() {
        const codeInSession = nativeWin.sessionStorage.getItem('wechatCode');
        if (!!codeInSession) {
            nativeWin.sessionStorage.removeItem('wechatCode');
            return codeInSession;
        }

        const codeOnUrl = URLHelper.current.search.code;
        if (!!codeOnUrl) {
            nativeWin.sessionStorage.setItem('wechatCode', codeOnUrl);

            const current = URLHelper.current.clone();
            const search = {
                ...current.search,
            };
            delete search.code;
            delete search.state;
            current.search = search;
            nativeWin.location.href = current.toString();
        } else {
            this.goAuth();
        }
        return '';
    }

    static get userInfo() {
        if (!user) {
            user = nativeWin?.sessionStorage.getItem(userCacheKey);
            if (!!user) {
                try {
                    user = JSON.parse(user);
                } catch (e) {
                    user = null;
                }
            }
        }
        return user ?? null;
    }

    static set userInfo(u) {
        user = u;
        if (!!u) {
            nativeWin.sessionStorage.setItem(userCacheKey, JSON.stringify(u));
        } else {
            nativeWin.sessionStorage.removeItem(userCacheKey);
        }
    }

    async static waitSDKReadyFunc(retry = 1) {
        if (!sdk) {
            await dynamicLoadScript('https://res.wx.qq.com/open/js/jweixin-1.6.0.js').catch(() => dynamicLoadScript('https://res2.wx.qq.com/open/js/jweixin-1.6.0.js'));

            const config = await this.getConfig();

            await new Promise((resolve, reject) => {
                nativeWin.wx.ready(() => {
                    sdk = nativeWin.wx;
                    resolve();
                });

                nativeWin.wx.error((res) => {
                    // config信息验证失败会执行error函数，如签名过期导致验证失败，具体错误信息可以打开config的debug模式查看，也可以在返回的res参数中查看，对于SPA可以在这里更新签名。
                    if (0 < retry) {
                        WechatHelper.waitSDKReadyFunc(retry - 1).then(resolve).catch(reject);
                    } else {
                        reject(res);
                    }
                });

                nativeWin.wx.config({
                    appId: config.appid, // 必填，公众号的唯一标识
                    timestamp: config.timestamp, // 必填，生成签名的时间戳
                    nonceStr: config.nonceStr, // 必填，生成签名的随机串
                    signature: config.signature,// 必填，签名
                    debug: this.debug, // 开启调试模式,调用的所有api的返回值会在客户端alert出来，若要查看传入的参数，可以在pc端打开，参数信息会通过log打出，仅在pc端时才会打印。
                    jsApiList: WechatHelper.JsSDKList, // 必填，需要使用的JS接口列表
                    openTagList: WechatHelper.customElement,
                });
            });
        }
    }

    async static waitSDKReady(retry = 1) {
        return sdk || sdkLoadingPromise || (sdkLoadingPromise = this.waitSDKReadyFunc(retry).then(() => sdk));
    }

    static async closeWindow_JsSDK() {
        const sdk = await WechatHelper.waitSDKReady();
        sdk.closeWindow();
    }

    static async openLocation_JsSDK(param) {
        const sdk = await WechatHelper.waitSDKReady();
        return new Promise((resolve, reject) => {
            sdk.openLocation({
                ...param,
                success: resolve,
                fail: reject,
            });
        });
    }

    static async getLocation_JsSDK(type) {
        const sdk = await WechatHelper.waitSDKReady();
        return new Promise((resolve, reject) => {
            sdk.getLocation({
                type,
                success(res) {
                    resolve(res);
                },
                fail: reject,
            });
        });
    }

    static async scanQRCode_JsSDK(param) {
        const sdk = await WechatHelper.waitSDKReady();
        return new Promise((resolve, reject) => {
            sdk.scanQRCode({
                ...param,
                success(res) {
                    resolve(res?.resultStr);
                },
                fail: reject,
            });
        });
    }

    static async chooseImage_JsSDK(param) {
        const sdk = await WechatHelper.waitSDKReady();
        return new Promise((resolve, reject) => {
            sdk.chooseImage({
                ...param,
                success(res) {
                    resolve(res?.localIds ?? []);
                },
                fail: reject,
            });
        });
    }

    static async uploadImage_JsSDK(param) {
        const sdk = await WechatHelper.waitSDKReady();
        return new Promise((resolve, reject) => {
            sdk.uploadImage({
                ...param,
                success(res) {
                    resolve(res?.serverId ?? '');
                },
                fail: reject,
            });
        });
    }

    static async getLocalImgData_JsSDK(localId) {
        const sdk = await WechatHelper.waitSDKReady();
        return new Promise((resolve, reject) => {
            sdk.getLocalImgData({
                localId,
                success(res) {
                    resolve(res?.localData ?? '');
                },
                fail: reject,
            });
        });
    }
}
